package com.example.Service;


import com.example.utils.VivoAuth;
import com.example.utils.WavMin;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.io.File;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 方言识别
 * 与实时短语音的请求发送方式不同
 * 与实时短语音相比多一个字段
 */
@Service
public class AsrDialectService {

    private static final String APP_ID = "2025985389";
    private static final String APP_KEY = "eAkRKtYXOawsmtVv";
    private static final String URI_PATH = "/asr/v2";
    private static final String METHOD = "GET";
    private static final String DOMAIN = "api-ai.vivo.com.cn";
    private static final int SAMPLE_FRAMES = 1280; // 每帧采样数
    private static final int NUM = 1;
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 错误码定义
    private static final Map<Integer, String> ERROR_CODES = new HashMap<>();
    static {
        ERROR_CODES.put(10000, "参数校验失败");
        ERROR_CODES.put(10002, "引擎服务异常");
        ERROR_CODES.put(10003, "获取中间识别结果失败");
        ERROR_CODES.put(10004, "获取最终识别结果失败");
        ERROR_CODES.put(10005, "解析引擎数据异常");
        ERROR_CODES.put(10006, "引擎内部错误");
        ERROR_CODES.put(10007, "请求nlu出错");
        ERROR_CODES.put(10008, "音频超长");
    }

    /**
     * 启动入口
     * @throws Exception
     */
    public String DialectRecognition(byte[] audioData) throws Exception {

        System.out.println("音频文件读取完成，大小: " + audioData.length + " 字节");

        System.out.println("开始转换音频格式...");
        byte[] pcmData = WavMin.convertAudio(audioData);
        System.out.println("音频格式转换完成，大小: " + pcmData.length + " 字节");

        long currentTime = System.currentTimeMillis();
        Map<String, String> params = new HashMap<>();
        params.put("client_version", "unknown");
        params.put("package", "unknown");
        params.put("user_id", "2addc42b7ae689dfdf1c63e220df52a2");
        params.put("sdk_version", "unknown");
        params.put("android_version", "unknown");
        params.put("system_time", String.valueOf(currentTime));
        params.put("net_type", "1");
        params.put("engineid", "shortasrinput");
        params.put("user_info", "0");

        System.out.println("生成签名头...");
        String queryString = buildQueryString(params);
        HttpHeaders headers = VivoAuth.generateAuthHeaders(APP_ID, APP_KEY, METHOD, URI_PATH, queryString);
        String url = buildWebSocketUrl(params);
        System.out.println("WebSocket URL: " + url);

        Map<String, Object> startData = new HashMap<>();
        startData.put("type", "started");
        startData.put("request_id", UUID.randomUUID().toString().replace("-", ""));

        Map<String, Object> asrInfo = new HashMap<>();
        asrInfo.put("front_vad_time", 6000);
        asrInfo.put("end_vad_time", 2000);
        asrInfo.put("audio_type", "pcm");
        asrInfo.put("chinese2digital", 1);
        asrInfo.put("punctuation", 2);
        asrInfo.put("lang", "dialect");
        asrInfo.put("mini_speech_time", 300);
        asrInfo.put("end_vad_time", 1440);

        startData.put("asr_info", asrInfo);
        startData.put("business_info", "{\"scenes_pkg\":\"com.tencent.qqlive\", \"editor_type\":\"3\", \"pro_id\":\"2addc42b7ae689dfdf1c63e220df52a2-2020\"}");

        System.out.println("开始处理音频数据...");
        String result = processAudioData(pcmData, url, headers, startData, currentTime);

        return result;
    }

    private String processAudioData(byte[] pcmData, String url, HttpHeaders headers, Map<String, Object> startData,
                                   long tbegin) throws Exception {
        CountDownLatch latch = new CountDownLatch(1);
        AtomicLong currentTime = new AtomicLong(tbegin);
        StringBuilder resultBuilder = new StringBuilder();
        AtomicBoolean isFirstResult = new AtomicBoolean(true);

        // 定义常量
        final int MAX_RETRIES = 3; // 最大重试次数
        final int RETRY_DELAY = 1000; // 重试延迟(ms)

        int retryCount = 0;
        AtomicBoolean success = new AtomicBoolean(false);

        while (retryCount < MAX_RETRIES && !success.get()) {
            try {
                WebSocketClient ws = new WebSocketClient(new URI(url)) {
                    private int firstWorld = 1;
                    private long firstWorldTime = 0;
                    private int cnt = 1;
                    private boolean isConnected = false;
                    private boolean hasReceivedResult = false;

                    @Override
                    public void onOpen(ServerHandshake handshakedata) {
                        System.out.println("WebSocket连接已建立");
                        isConnected = true;
                        try {
                            // 发送启动消息
                            String startMessage = objectMapper.writeValueAsString(startData);
                            System.out.println("发送启动消息: " + startMessage);
                            send(startMessage);

                            // 计算总帧数
                            int totalFrames = pcmData.length;
                            System.out.println("音频总帧数: " + totalFrames);

                            int curFrames = 0;
                            while (curFrames < totalFrames) {
                                if (!isConnected) {
                                    System.out.println("连接已断开，停止发送数据");
                                    break;
                                }

                                int remaining = totalFrames - curFrames;
                                int numSamples = Math.min(SAMPLE_FRAMES, remaining);

                                byte[] frame = Arrays.copyOfRange(pcmData, curFrames, curFrames + numSamples);
                                curFrames += numSamples;

                                if (frame.length < SAMPLE_FRAMES) {
                                    break;
                                }

                                send(frame);
                                Thread.sleep(40); // 模拟40ms的延迟

                                if (curFrames % (SAMPLE_FRAMES * 10) == 0) {
                                    System.out.println("已发送 " + curFrames + "/" + totalFrames + " 帧");
                                }
                            }

                            if (isConnected) {
                                // 发送结束标记
                                send("--end--".getBytes());
                                Thread.sleep(20);
                                send("--close--".getBytes());
                                System.out.println("音频数据发送完成");
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onMessage(String message) {
                        try {
                            Map<String, Object> response = objectMapper.readValue(message, Map.class);
                            String action = (String) response.get("action");
                            int code = (int) response.get("code");

                            if (code != 0) {
                                String errorDesc = ERROR_CODES.getOrDefault(code, "未知错误");
                                System.out.printf("[错误] 错误码: %d, 描述: %s%n", code, errorDesc);
                                return;
                            }

                            if ("error".equals(action) || "vad".equals(action)) {
                                String sid = (String) response.get("sid");
                                String desc = (String) response.get("desc");
                                String time = dateFormat.format(new Date());
                                System.out.printf("[状态] %s %s %s %s%n", sid, desc, time);
                            } else if ("result".equals(action) && "asr".equals(response.get("type"))) {
                                hasReceivedResult = true;
                                Map<String, Object> data = (Map<String, Object>) response.get("data");
                                String text = (String) data.get("text");
                                boolean isLast = (boolean) data.get("is_last");

                                if (text != null && !text.trim().isEmpty()) {
                                    if (firstWorld == 1) {
                                        firstWorldTime = System.currentTimeMillis() - currentTime.get();
                                        firstWorld = 0;
                                    }

                                    if (isLast) {
                                        String sid = (String) response.get("sid");
                                        String rid = (String) response.getOrDefault("request_id", "NULL");
                                        String desc = (String) response.get("desc");
                                        long t1 = firstWorldTime;
                                        long t2 = System.currentTimeMillis() - currentTime.get();
                                        String time = dateFormat.format(new Date());

                                        System.out.println("\n[识别结果]");
                                        System.out.println(text);
                                        resultBuilder.append(text); // 保存识别结果
                                        System.out.println("\n[识别信息]");
                                        System.out.printf("请求ID: %s%n", rid);
                                        System.out.printf("会话ID: %s%n", sid);
                                        System.out.printf("首字时间: %dms%n", t1);
                                        System.out.printf("总耗时: %dms%n", t2);
                                        System.out.printf("完成时间: %s%n", time);

                                        firstWorld = 1;
                                        currentTime.set(System.currentTimeMillis());
                                        cnt++;

                                        if (cnt > NUM) {
                                            success.set(true);
                                            latch.countDown();
                                        }
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onClose(int code, String reason, boolean remote) {
                        System.out.println("连接已关闭，code=" + code + ", reason=" + reason);
                        isConnected = false;
                        if (!hasReceivedResult) {
                            System.out.println("未收到任何识别结果，将进行重试");
                        }
                        latch.countDown();
                    }

                    @Override
                    public void onError(Exception ex) {
                        System.out.println("发生错误: " + ex.getMessage());
                        ex.printStackTrace();
                        isConnected = false;
                        String time = dateFormat.format(new Date());
                        System.out.printf("%s exception %s%n", time);
                        latch.countDown();
                    }
                };

                // 设置请求头
                for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
                    ws.addHeader(entry.getKey(), entry.getValue().get(0));
                }

                System.out.println("开始连接WebSocket服务器...");
                ws.connect();

                // 等待结果或超时
                int maxWaitTime = 30000; // 30秒超时
                int interval = 100; // 检查间隔
                for (int i = 0; i < maxWaitTime && !success.get(); i += interval) {
                    if (latch.getCount() == 0) {
                        break;
                    }
                    Thread.sleep(interval);
                }

                if (!success.get()) {
                    System.out.println("等待超时，未收到识别结果");
                    ws.close();
                }

            } catch (Exception e) {
                System.out.println("第" + (retryCount + 1) + "次尝试失败: " + e.getMessage());
                retryCount++;
                if (retryCount < MAX_RETRIES) {
                    System.out.println("等待" + RETRY_DELAY + "ms后重试...");
                    Thread.sleep(RETRY_DELAY);
                }
            }
        }

        if (!success.get()) {
            throw new RuntimeException("ASR请求失败，已重试" + MAX_RETRIES + "次");
        }
        
        return resultBuilder.toString(); // 返回最终的识别结果
    }

    private String buildQueryString(Map<String, String> params) {
        StringBuilder queryString = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (!first) {
                queryString.append("&");
            }
            queryString.append(entry.getKey())
                    .append("=")
                    .append(entry.getValue());
            first = false;
        }
        return queryString.toString();
    }

    private String buildWebSocketUrl(Map<String, String> params) {
        return "wss://" + DOMAIN + URI_PATH + "?" + buildQueryString(params);
    }

    private byte[] readAudioFile(String filePath) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException("音频文件不存在: " + filePath);
        }
        return Files.readAllBytes(Paths.get(filePath));
    }

}
